package net.jacqeush.mini.rpc.client;

import net.jacqeush.mini.rpc.client.proxy.RpcAsyncProxy;
import net.jacqeush.mini.rpc.client.proxy.RpcProxyImpl;

import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Jacquesh
 * @version 1.0
 * @date 2020/10/16 3:04
 */
public class Client {
    private static volatile Client client;
    private  String socketAddress;
    private Map<Class<?>,Object> syncProxyInstanceMap=new ConcurrentHashMap<Class<?>,Object>();
    private Map<Class<?>,Object> asyncProxyInstanceMap=new ConcurrentHashMap<Class<?>,Object>();
    private List<String> serverAddressList;
    private long timeout;
    private  RpcConnectManager manager;
    public static Client getInstance(){
        if(client==null){
            synchronized (Client.class){
                if(client==null){
                    client=new Client();
                }
            }
        }
        return  client;
    }
    public Client initialize(String serverAddress, long timeout) {
        Client.getInstance().socketAddress = serverAddress;
        Client.getInstance().timeout = timeout;
        Client.getInstance().manager=RpcConnectManager.getInstance();
        Client.getInstance().connect();
        return Client.getInstance();
    }
    public <T> T invokeSync(Class<T> interfaceClass) {
        if (syncProxyInstanceMap.containsKey(interfaceClass)) {
            return (T) syncProxyInstanceMap.get(interfaceClass);
        } else {
            Object proxy = Proxy.newProxyInstance(
                    interfaceClass.getClassLoader(),
                    new Class<?>[]{interfaceClass},
                    new RpcProxyImpl<>(manager, interfaceClass, timeout)
            );
            syncProxyInstanceMap.put(interfaceClass, proxy);
            return (T) proxy;
        }
    }

    @SuppressWarnings("unchecked")
    public <T> RpcAsyncProxy invokeAsync(Class<T> interfaceClass) {
        if (asyncProxyInstanceMap.containsKey(interfaceClass)) {
            return ((RpcProxyImpl<T>) asyncProxyInstanceMap.get(interfaceClass));
        } else {
            RpcProxyImpl<T> rpcProxyImpl = new RpcProxyImpl<T>(manager, interfaceClass, timeout);
            asyncProxyInstanceMap.put(interfaceClass, rpcProxyImpl);
            return rpcProxyImpl;
        }
    }
  public void connect(){
      Client.getInstance().manager.connect(Client.getInstance().socketAddress);
   }


  void stop(){
      Client.getInstance().manager.close();
    }
}
